/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package BusinessLogic;

import Entity.*;
import EntityState.*;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.Resource;
import javax.ejb.Stateless;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.JMSException;
import javax.jms.MapMessage;
import javax.jms.MessageProducer;
import javax.jms.Queue;
import javax.jms.Session;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.fileupload.FileItem;
import org.joda.time.DateTime;

/**
 *
 * @author James
 */
@Stateless
public class PartnerBean implements PartnerBeanLocal {
    //Resources
    @Resource(mappedName = "jms/QueueConnectionFactory")
    private ConnectionFactory queueConnectionFactory;
    @Resource(mappedName = "jms/OutgoingMailQueue")
    private Queue emailQueue;
    @PersistenceContext(unitName = "TCube-ejbPU")
    private EntityManager em;

    @Override
    public ArrayList getInfo(int action, long id) {
        ArrayList list = new ArrayList();
        
        if (action == Constants.GET_PARTNER_PROFILE) {
            Partner p = em.find(Partner.class, id);
            if (p == null) list.add(Constants.STATUS_NOT_FOUND);
            else {
                PartnerState ps = new PartnerState(p.getId(), p.getName(), p.getBusinessAddress1(), p.getBusinessAddress2(), p.getBusinessPostalCode(), p.getBillingAddress1(), p.getBillingAddress2(), p.getBillingPostalCode(), p.getCountryCode(), p.getPhone(), p.getCountry(), p.getProvince(), p.getCity(), p.getTimezone(), p.getBusinessEmail(), p.getNotificationURL(), p.getServicePlanTaken(), p.getRegisteredDate(), p.getSector(), p.getRatedPoint(), p.getNumOfRater(), p.getReservationNoShowFee(), p.getReservationCancelFee(), p.getReservableMinimumLength(), p.getReservableMaximumLength(), p.getReservationMinimumLeadTime(), p.getReservationMaximumLeadTime());
                list.add(Constants.STATUS_SUCCESSFUL);
                list.add(ps);
            }
            
        } else if (action == Constants.GET_LIST_OF_BRANCHES) {
            Partner p = em.find(Partner.class, id);
            if (p == null) list.add(Constants.STATUS_NOT_FOUND);
            else {
                List<Partner> listOfBranches = p.getListOfBranches();
                List<PartnerState> branches = new ArrayList<PartnerState>();
                for (Partner branch : listOfBranches) {
                    PartnerState ps = new PartnerState(branch.getId(), branch.getName(), branch.getSector(), branch.getRatedPoint(), branch.getNumOfRater());
                    branches.add(ps);
                }
                list.add(Constants.STATUS_SUCCESSFUL);
                list.add(branches);
            }
            
        } else if (action == Constants.GET_LIST_OF_OUTLETS) {
            Partner p = em.find(Partner.class, id);
            if (p == null) list.add(Constants.STATUS_NOT_FOUND);
            else {
                List<Outlet> listOfOutlets = p.getListOfOutlets();
                List<OutletState> outlets = new ArrayList<OutletState>();
                for (Outlet outlet : listOfOutlets) {
                    if (!outlet.isDeleted()) {
                        OutletState os = new OutletState(outlet.getId(), outlet.getName(), outlet.isActive());
                        outlets.add(os);
                    }
                }
                list.add(Constants.STATUS_SUCCESSFUL);
                list.add(outlets);
            }
            
        } else if (action == Constants.GET_OUTLET_PROFILE) {
            Outlet o = em.find(Outlet.class, id);
            if (o == null || o.isDeleted()) list.add(Constants.STATUS_NOT_FOUND);
            else {
                // Get the layout
                Files layout = o.getLayout();
                FileState layoutState = new FileState(layout.getId(), layout.getName(), layout.getLocation(), layout.getDescription(), layout.getCreatedDate());
                
                // Get list of pictures
                List<Files> listOfPictures = o.getListOfPictures();
                List<FileState> pictures   = new ArrayList<FileState>();
                for (Files picture : listOfPictures) {
                    FileState fs = new FileState(picture.getId(), picture.getName(), picture.getLocation(), picture.getDescription(), picture.getCreatedDate());
                    pictures.add(fs);
                }
                
                OutletState os = new OutletState(o.getId(), o.getName(), o.getAddress1(), o.getAddress2(), o.getPostalCode(), o.getCountryCode(), o.getPhone(), o.getCountry(), o.getProvince(), o.getCity(), o.getTimezone(), o.getBusinessEmail(), o.getReservationNoShowFee(), o.getReservationCancelFee(), o.getReservableMinimumLength(), o.getReservableMaximumLength(), o.getReservationMinimumLeadTime(), o.getReservationMaximumLeadTime(), o.isActive(), layoutState, pictures);
                list.add(Constants.STATUS_SUCCESSFUL);
                list.add(os);
            }
            
        } else if (action == Constants.GET_LIST_OF_PARTNER_CATEGORIES) {
            Partner p = em.find(Partner.class, id);
            if (p == null) list.add(Constants.STATUS_NOT_FOUND);
            else {
                List<ItemCategory> listOfItemCategories = p.getItemCategories();
                List<ItemCategoryState> categories = new ArrayList<ItemCategoryState>();
                for (ItemCategory category : listOfItemCategories) {
                    if (!category.isDeleted()) {
                        List<Item> listOfItems = category.getListOfItems();
                        List<ItemState> items  = new ArrayList<ItemState>();
                        for (Item item : listOfItems) {
                            if (!item.isDeleted()) {
                                ItemState is = new ItemState(item.getId(), item.getName(), item.getType());
                                items.add(is);
                            }
                        }
                        ItemCategoryState ics = new ItemCategoryState(category.getId(), category.getName(), category.getDescription(), category.getDiscount(), category.getCreatedDate(), category.isActive(), items);
                        categories.add(ics);
                    }
                }
                list.add(Constants.STATUS_SUCCESSFUL);
                list.add(categories);
            }
            
        } else if (action == Constants.GET_LIST_OF_OUTLET_CATEGORIES) {
            Outlet o = em.find(Outlet.class, id);
            if (o == null || o.isDeleted()) list.add(Constants.STATUS_NOT_FOUND);
            else {
                List<ItemCategory> listOfItemCategories = o.getItemCategories();
                List<ItemCategoryState> categories = new ArrayList<ItemCategoryState>();
                for (ItemCategory category : listOfItemCategories) {
                    if (!category.isDeleted()) {
                        List<Item> listOfItems = category.getListOfItems();
                        List<ItemState> items  = new ArrayList<ItemState>();
                        for (Item item : listOfItems) {
                            if (!item.isDeleted()) {
                                ItemState is = new ItemState(item.getId(), item.getName(), item.getType());
                                items.add(is);
                            }
                        }
                        ItemCategoryState ics = new ItemCategoryState(category.getId(), category.getName(), category.getDescription(), category.getDiscount(), category.getCreatedDate(), category.isActive(), items);
                        categories.add(ics);
                    }
                }
                list.add(Constants.STATUS_SUCCESSFUL);
                list.add(categories);
            }
            
        } else if (action == Constants.GET_ITEM_CATEGORY_INFO) {
            ItemCategory ic = em.find(ItemCategory.class, id);
            if (ic == null || ic.isDeleted()) list.add(Constants.STATUS_NOT_FOUND);
            else {
                List<Item> listOfItems = ic.getListOfItems();
                List<ItemState> items  = new ArrayList<ItemState>();
                for (Item item : listOfItems) {
                    if (!item.isDeleted()) {
                        ItemDetailsState ids = null;
                        for (ItemDetails details : item.getListOfItemDetails()) {
                            if (details.getStoppedDate() == 0) {
                                ids = new ItemDetailsState(details.getId(), details.getDiscount(), details.getPrice(), details.getRedeemPrice(), details.getAdditionalLoyaltyPoint(), details.getStartedDate());
                                break;
                            }
                        }
                        ItemState is = new ItemState(item.getId(), item.getName(), item.getDescription(), item.getLastMonthNumOfBuyers(), item.getNumOfBuyers(), item.isActive(), item.getCreatedDate(), ids);
                        items.add(is);
                    }
                }
                ItemCategoryState ics = new ItemCategoryState(ic.getId(), ic.getName(), ic.getDescription(), ic.getDiscount(), ic.getCreatedDate(), ic.isActive(), items);
                list.add(Constants.STATUS_SUCCESSFUL);
                list.add(ics);
            }
            
        } else if (action == Constants.GET_LIST_OF_OUTLET_ITEMS) {
            Outlet o = em.find(Outlet.class, id);
            if (o == null || o.isDeleted()) list.add(Constants.STATUS_NOT_FOUND);
            else {
                List<ItemState> items = new ArrayList<ItemState>();
                
                // Include all items from this outlet 
                List<ItemCategory> listOfItemCategories = o.getItemCategories();
                for (ItemCategory category : listOfItemCategories) {
                    if (!category.isDeleted()) {
                        ItemCategoryState ics = new ItemCategoryState(category.getId(), category.getName());
                        List<Item> listOfItems = category.getListOfItems();
                        for (Item item : listOfItems) {
                            if (item.isDeleted()) {
                                ItemState is = new ItemState(item.getId(), item.getName(), item.getType(), ics);
                                items.add(is);
                            }
                        }
                    }
                }
                
                // Include all items from the partner
                listOfItemCategories = o.getPartner().getItemCategories();
                for (ItemCategory category : listOfItemCategories) {
                    if (!category.isDeleted()) {
                        ItemCategoryState ics = new ItemCategoryState(category.getId(), category.getName());
                        List<Item> listOfItems = category.getListOfItems();
                        for (Item item : listOfItems) {
                            if (!item.isDeleted()) {
                                ItemState is = new ItemState(item.getId(), item.getName(), item.getType(), ics);
                                items.add(is);
                            }
                        }
                    }
                }
                
                list.add(Constants.STATUS_SUCCESSFUL);
                list.add(items);
            }
            
        } else if (action == Constants.GET_LIST_OF_PARTNER_ITEMS) {
            Partner p = em.find(Partner.class, id);
            if (p == null || p.isDeleted()) list.add(Constants.STATUS_NOT_FOUND);
            else {
                List<ItemState> items = new ArrayList<ItemState>();
                
                // Include all items from this outlet 
                List<ItemCategory> listOfItemCategories = p.getItemCategories();
                for (ItemCategory category : listOfItemCategories) {
                    if (!category.isDeleted()) {
                        ItemCategoryState ics = new ItemCategoryState(category.getId(), category.getName());
                        List<Item> listOfItems = category.getListOfItems();
                        for (Item item : listOfItems) {
                            if (!item.isDeleted()) {
                                ItemState is = new ItemState(item.getId(), item.getName(), item.getType(), ics);
                                items.add(is);
                            }
                        }
                    }
                }
                
                list.add(Constants.STATUS_SUCCESSFUL);
                list.add(items);
            }
            
        } else if (action == Constants.GET_DETAILED_ITEM_INFO) {
            Item i = em.find(Item.class, id);
            if (i == null || i.isDeleted()) list.add(Constants.STATUS_NOT_FOUND);
            else {
                // Get the latest item details
                ItemDetailsState ids = null;
                for (ItemDetails details : i.getListOfItemDetails()) {
                    if (details.getStoppedDate() == 0) {
                        List<Item> listOfSubItems = details.getSubItems();
                        List<ItemState> subItems  = new ArrayList<ItemState>();
                        for (Item subItem : listOfSubItems) {
                            ItemState item = new ItemState(subItem.getId(), subItem.getName(), subItem.getType());
                            subItems.add(item);
                        }
                        ids = new ItemDetailsState(details.getId(), details.getDiscount(), details.getPrice(), details.getRedeemPrice(), details.getAdditionalLoyaltyPoint(), details.getStartedDate(), subItems);
                        break;
                    }
                }
                
                // Get list of pictures
                List<Files> listOfPictures = i.getListOfPictures();
                List<FileState> pictures   = new ArrayList<FileState>();
                for (Files picture : listOfPictures) {
                    FileState fs = new FileState(picture.getId(), picture.getName(), picture.getLocation(), picture.getDescription(), picture.getCreatedDate());
                    pictures.add(fs);
                }
                
                ItemState is = new ItemState(i.getId(), i.getName(), i.getDescription(), i.getLastMonthNumOfBuyers(), i.getNumOfBuyers(), i.isActive(), i.getCreatedDate(), ids, pictures);
                list.add(Constants.STATUS_SUCCESSFUL);
                list.add(is);        
            }
            
        } else if (action == Constants.GET_LIST_OF_RESERVABLE_UNITS) {
            Outlet o = em.find(Outlet.class, id);
            if (o == null || o.isDeleted()) list.add(Constants.STATUS_NOT_FOUND);
            else {
                List<ReservableUnit> listOfReservableUnits = o.getListOfReservationUnits();
                List<ReservableUnitState> reservableUnits  = new ArrayList<ReservableUnitState>();
                for (ReservableUnit unit : listOfReservableUnits) {
                    if (!unit.isDeleted()) {
                        Item reservedItem = unit.getReservedItem();
                        ItemState is = new ItemState(reservedItem.getId(), reservedItem.getName(), reservedItem.getType());
                        ReservableUnitState rus = new ReservableUnitState(unit.getId(), unit.getName(), unit.getDescription(), unit.isActive(), is);
                        reservableUnits.add(rus);
                    }
                }
                list.add(Constants.STATUS_SUCCESSFUL);
                list.add(reservableUnits);
            }
        
        } else if (action == Constants.GET_RESERVABLE_UNIT_INFO) {
            ReservableUnit ru = em.find(ReservableUnit.class, id);
            if (ru == null || ru.isDeleted()) list.add(Constants.STATUS_NOT_FOUND);
            else {
                // Get the latest reservableUnit details
                ReservableUnitDetailsState details = null;
                for (ReservableUnitDetails rud : ru.getListOfReservableUnitDetails()) {
                    if (rud.getStoppedDate() == 0) {
                        details = new ReservableUnitDetailsState(rud.getId(), rud.getReservationNoShowFee(), rud.getReservationCancelFee(), rud.getReservableMinimumLength(), rud.getReservableMaximumLength(), rud.getReservationMinimumLeadTime(), rud.getReservationMaximumLeadTime(), rud.getNumOfCustomersPerUnit(), rud.getNumOfAvailableUnits(), rud.getStartedDate());
                        break;
                    }
                }
                
                // Get the layout
                Files layout = ru.getLayout();
                FileState layoutState = new FileState(layout.getId(), layout.getName(), layout.getLocation(), layout.getDescription(), layout.getCreatedDate());
                
                // Get list of pictures
                List<Files> listOfPictures = ru.getListOfPictures();
                List<FileState> pictures   = new ArrayList<FileState>();
                for (Files picture : listOfPictures) {
                    FileState fs = new FileState(picture.getId(), picture.getName(), picture.getLocation(), picture.getDescription(), picture.getCreatedDate());
                    pictures.add(fs);
                }
                
                // Get reservedItem
                Item reservedItem = ru.getReservedItem();
                ItemState is = new ItemState(reservedItem.getId(), reservedItem.getName(), reservedItem.getType());
                
                ReservableUnitState rus = new ReservableUnitState(ru.getId(), ru.getName(), ru.getDescription(), ru.isActive(), ru.getCurrentMonth(), ru.getCurrentYear(), ru.getCurrentMonthArray(), ru.getFirstMonth(), ru.getSecondMonth(), ru.getThirdMonth(), ru.getFourthMonth(), layoutState, is, details, pictures);
                list.add(Constants.STATUS_SUCCESSFUL);
                list.add(rus);
            }
            
        }
        
        return list;
    }
    
    @Override
    public int delete(int target, long id) {
        if (target == Constants.DELETE_TARGET_ITEM_CATEGORY) {
            ItemCategory ic = em.find(ItemCategory.class, id);
            if (ic == null) return Constants.STATUS_NOT_FOUND;
            else {
                // Update active and deleted status
                ic.setActive(false);
                ic.setDeleted(true);
                
                // Delete all component items
                for (Item i : ic.getListOfItems()) delete(Constants.DELETE_TARGET_ITEM, i.getId());
                
                return Constants.STATUS_SUCCESSFUL;
            }
            
        } else if (target == Constants.DELETE_TARGET_ITEM) {
            Item i = em.find(Item.class, id);
            if (i == null) return Constants.STATUS_NOT_FOUND;
            else {
                // Update active and deleted status
                i.setActive(false);
                i.setDeleted(true);
                
                // A lot more things to do here
                
                return Constants.STATUS_SUCCESSFUL;
            }
            
        } else return Constants.STATUS_INVALID_INPUT;
    }
    
    @Override
    public int addReservableUnit(String name, String description, int numOfCustomersPerUnit, int numOfAvailableUnits, long itemID, long outletID, HashMap pictures, HashMap pictDescriptions, FileItem layout) throws Exception {
        Outlet theOutlet = em.find(Outlet.class, outletID);
        if (theOutlet == null) return Constants.STATUS_NOT_FOUND;
        else {
            ReservableUnit ru = new ReservableUnit();
            
            //Get the reserved Item
            Item reservedItem = null;
            if (itemID != 0 && (reservedItem = em.find(Item.class, itemID)) == null) return Constants.STATUS_NOT_FOUND;
            
            // Get the list of pictures
            String path, uniqueName;
            File file;
            
            Set<String> keySet = pictures.keySet();
            for (String key : keySet) {
                Object ob = pictures.get(key);
                FileItem picture;
                if (ob == null) continue;
                else picture = (FileItem) ob;
                
                // Look for a unique name for the picture
                String picType = picture.getContentType().substring(picture.getContentType().indexOf("/")+1);
                do {
                    uniqueName = getUniqueID();
                    path       = Constants.FOLDER_PARTNER_IMAGE + uniqueName + "." + picType;
                    file  = new File(path);
                } while (file.exists());
                // Write to disk and Record the picture's information into database
                picture.write(file);
                Files  thePicture      = new Files();
                String pictDescription = (String) pictDescriptions.get("description"+picture.getFieldName());
                path = ".." + path.substring(path.indexOf("\\partner\\"));
                path = path.replace("\\", "/");
                thePicture.createFile(uniqueName, path, pictDescription);
                em.persist(thePicture);
                em.flush();
                ru.addPicture(thePicture);
            }
            
            // Get the layout
            Files theLayout = null;
            if (layout != null) {
                String picType = layout.getContentType().substring(layout.getContentType().indexOf("/")+1);
                do {
                    uniqueName = getUniqueID();
                    path       = Constants.FOLDER_PARTNER_IMAGE + uniqueName + "." + picType;
                    file  = new File(path);
                } while (file.exists());
                // Write to disk and Record the layout's information into database
                layout.write(file);
                theLayout = new Files();
                path = ".." + path.substring(path.indexOf("\\partner\\"));
                path = path.replace("\\", "/");
                theLayout.createFile(uniqueName, path, "");
                em.persist(theLayout);
                em.flush();
            }
            
            // Persist the outlet
            ru.createReservableUnit(name, description, numOfCustomersPerUnit, numOfAvailableUnits, theLayout, reservedItem, theOutlet);
            em.persist(ru);
            theOutlet.addReservableUnit(ru);
            return Constants.STATUS_SUCCESSFUL;
        }
    }
    
    @Override
    public int addOutlet(String name, String address1, String address2, String postalCode, String countryCode, String phone, String country, String province, String city, String businessEmail, long partnerID, HashMap pictures, HashMap pictDescriptions, FileItem layout) throws Exception {
        Partner thePartner = em.find(Partner.class, partnerID);
        if (thePartner == null) return Constants.STATUS_NOT_FOUND;
        else {
            Outlet o = new Outlet();
    
            // Get the list of pictures
            String path, uniqueName;
            File file;
            Set<String> keySet = pictures.keySet();
            for (String key : keySet) {
                Object ob = pictures.get(key);
                FileItem picture;
                if (ob == null) continue;
                else picture = (FileItem) ob; 
                
                // Look for a unique name for the picture
                String picType = picture.getContentType().substring(picture.getContentType().indexOf("/")+1);
                do {
                    uniqueName = getUniqueID();
                    path       = Constants.FOLDER_PARTNER_IMAGE + uniqueName + "." + picType;
                    file  = new File(path);
                } while (file.exists());
                // Write to disk and Record the picture's information into database
                picture.write(file);
                Files  thePicture      = new Files();
                String pictDescription = (String) pictDescriptions.get("description"+picture.getFieldName());
                path = ".." + path.substring(path.indexOf("\\partner\\"));
                path = path.replace("\\", "/");
                thePicture.createFile(uniqueName, path, pictDescription);
                em.persist(thePicture);
                em.flush();
                o.addPicture(thePicture);
            }
            
            // Get the layout
            Files theLayout = null;
            if (layout != null) {
                String picType = layout.getContentType().substring(layout.getContentType().indexOf("/")+1);
                do {
                    uniqueName = getUniqueID();
                    path       = Constants.FOLDER_PARTNER_IMAGE + uniqueName + "." + picType;
                    file  = new File(path);
                } while (file.exists());
                // Write to disk and Record the layout's information into database
                layout.write(file);
                theLayout = new Files();
                path = ".." + path.substring(path.indexOf("\\partner\\"));
                path = path.replace("\\", "/");
                theLayout.createFile(uniqueName, path, "");
                em.persist(theLayout);
                em.flush();
            }
            
            // Persist the outlet
            o.createOutlet(name, address1, address2, postalCode, countryCode, phone, country, province, city, businessEmail, theLayout, thePartner);
            em.persist(o);
            thePartner.addOutlet(o);
            return Constants.STATUS_SUCCESSFUL;
        }
    }
    
    @Override
    public int addItemCategory(String name, String description, long partnerID, long outletID) {
        ItemCategory ic = new ItemCategory();
        if (partnerID != 0) {
            Partner thePartner = em.find(Partner.class, partnerID);
            if (thePartner == null) return Constants.STATUS_NOT_FOUND;
            else {
                ic.createItemCategory(name, description, thePartner, null);
                thePartner.addItemCategory(ic);
            } 
        } else {
            Outlet theOutlet = em.find(Outlet.class, outletID);
            if (theOutlet == null) return Constants.STATUS_NOT_FOUND;
            else {
                ic.createItemCategory(name, description, null, theOutlet);
                theOutlet.addItemCategory(ic);
            }  
        }
        em.persist(ic);
        return Constants.STATUS_SUCCESSFUL;
    }
    
    @Override
    public int addTerm(String name, String content, long partnerID) {
        TermsAndConditions tac = new TermsAndConditions();
        Partner thePartner = em.find(Partner.class, partnerID);
        if (thePartner == null) return Constants.STATUS_NOT_FOUND;
        else {
            tac.createTermsAndConditions(name, content);
            thePartner.addTermsAndConditions(tac);
        } 
        em.persist(tac);
        return Constants.STATUS_SUCCESSFUL;
    }
    
    
    public int activateCube(long cubeID) {
        return Constants.STATUS_SUCCESSFUL;
    }
    
    @Override
    public int addItem(String name, String description, HashMap pictures, HashMap pictDescriptions, int type, int discount, int price, int redeemPrice, int additionalLoyaltyPoint, int maxNumberOfBuyers, boolean selling, long[] subItemIDs, long categoryID, long termID) throws Exception {
        ItemCategory         ic = em.find(ItemCategory.class, categoryID);
        TermsAndConditions term = null;
        if (ic == null || (termID != 0 && (term = em.find(TermsAndConditions.class, termID)) == null)) return Constants.STATUS_NOT_FOUND;
        else {
            // Create an item according to the type
            Item i = null;
            if (type == Constants.ITEM_TYPE_NORMAL) {
                i = new Item();
            } else if (type == Constants.ITEM_TYPE_CUBE) {
                i = new Cubes();
            } else return Constants.STATUS_INVALID_INPUT;
            
            // Get information that is similar in all items
                // Get the list of sub items 
                List<Item> subItems = new ArrayList<Item>();
                if (subItemIDs != null) {
                    for (long itemID : subItemIDs) {
                        Item subItem = em.find(Item.class, itemID);
                        if (subItem == null) return Constants.STATUS_NOT_FOUND;
                        else subItems.add(subItem);
                    }
                }

                // Get the list of pictures
                Set<String> keySet = pictures.keySet();
                for (String key : keySet) {
                    Object o = pictures.get(key);
                    FileItem picture;
                    if (o == null) continue;
                    else picture = (FileItem) o; 
                    
                    // Look for a unique name for the picture
                    String path, uniqueName;
                    File pic;
                    String picType = picture.getContentType().substring(picture.getContentType().indexOf("/")+1);
                    do {
                        uniqueName = getUniqueID();
                        path       = Constants.FOLDER_PARTNER_IMAGE + uniqueName + "." + picType;
                        pic  = new File(path);
                    } while (pic.exists());
                    // Write to disk and Record the layout's information into database
                    picture.write(pic);
                    Files  thePicture      = new Files();
                    String pictDescription = (String) pictDescriptions.get("description"+picture.getFieldName());
                    path = ".." + path.substring(path.indexOf("\\partner\\"));
                    path = path.replace("\\", "/");
                    thePicture.createFile(uniqueName, path, pictDescription);
                    em.persist(thePicture);
                    em.flush();
                    i.addPicture(thePicture);
                }
                
            if (type == Constants.ITEM_TYPE_NORMAL) {
                // Persist the normal item
                i.createItem(name, description, type, discount, price, redeemPrice, additionalLoyaltyPoint, selling, ic, subItems);
                em.persist(i);
            } else if (type == Constants.ITEM_TYPE_CUBE) {
                // Persist the cube item
                Cubes cube = (Cubes) i;
                cube.createCube(name, description, type, discount, price, additionalLoyaltyPoint, maxNumberOfBuyers, true, ic, term, subItems);
                em.persist(cube);
            }
            ic.addItem(i);
            
            return Constants.STATUS_SUCCESSFUL;
        }
    }

    @Override
    public int checkAvailability(String username) {
        if (em.find(PartnerAccount.class, username) == null) return Constants.STATUS_SUCCESSFUL;
        else return Constants.STATUS_FAILED; 
    }

    @Override
    public int registerAccount(String username, String password, String IC, String firstName, String lastName, String gender, String countryCode, String phone, String email, String country, String province, String city, int accountLevel, int[] listOfPrivileges, long partnerID, long outletID) {
        //Check if the database contains user with same NRIC or email
        Query q = em.createQuery("SELECT P FROM PartnerAccount P WHERE P.IC=:IC OR P.email=:email OR P.username=:username");
        q.setParameter("IC", IC);
        q.setParameter("email", email);
        q.setParameter("username", username);

        //If this user is unique, create an entry
        if (!q.getResultList().isEmpty()) return Constants.STATUS_NOT_UNIQUE;
        else {
            Partner thePartner = null;
            if (partnerID != 0) thePartner = em.find(Partner.class, partnerID);
            Outlet  theOutlet  = null;
            if (outletID != 0) theOutlet = em.find(Outlet.class, outletID);
            PartnerAccount pa = new PartnerAccount();
            List<PartnerPrivilege> privileges = new ArrayList<PartnerPrivilege>();
            for (int i : listOfPrivileges) {
                PartnerPrivilege pp = em.find(PartnerPrivilege.class, i);
                if (pp != null) {
                    privileges.add(pp);
                }
            }
            pa.createPartnerAccount(username, DigestUtils.sha256Hex(password), IC, firstName, lastName, gender, countryCode, phone, email, country, province, city, accountLevel, privileges, thePartner, theOutlet);
            String id = getUniqueID();
            while (em.find(InactivatedPartnerAccount.class, id) != null) id = getUniqueID(); 
            InactivatedPartnerAccount ip = new InactivatedPartnerAccount(id, pa);
            em.persist(ip);
            em.flush();
            String link = "http://localhost:8080/portal/business/PartnerAccountActivation?id=" + id; 
            sendEmail(Constants.MAIL_ACTIVATION, email, link);
            return Constants.STATUS_SUCCESSFUL;
        }
    }

    @Override
    public int activateUser(String id) {
        InactivatedPartnerAccount ip = em.find(InactivatedPartnerAccount.class, id);
        if (ip == null) return Constants.STATUS_NOT_FOUND;
        else {
            ip.getAccount().setActivated(true);
            em.remove(ip);
            return Constants.STATUS_SUCCESSFUL;
        }
    }

    @Override
    public PartnerAccountState login(String username, String password, String timezone) {
        PartnerAccount pa = em.find(PartnerAccount.class, username);
        if (pa == null || !pa.getPassword().equals(DigestUtils.sha256Hex(password))) return null;
        else {
            PartnerAccountState pas;
            if (pa.isActive() && pa.isActivated()) {
                if (!pa.getTimezone().equals(timezone)) pa.setTimezone(timezone); //Update timezone everytime a user log in
                
                // Create the State objects
                List<PartnerPrivilegeState> listOfPrivileges = new ArrayList<PartnerPrivilegeState>();
                for (PartnerPrivilege pp : pa.getListOfPrivileges()) {
                    PartnerPrivilegeState pps = new PartnerPrivilegeState(pp.getId(), pp.getName(), pp.getDescription(), pp.getCreatedDate());
                    listOfPrivileges.add(pps);
                }
                
                // Get the Partner or Outlet State
                PartnerState ps = null;
                OutletState  os = null;
                if (pa.getPartner() != null) {
                    Partner p = pa.getPartner();
                    ps = new PartnerState(p.getId(), p.getName(), p.getSector(), p.getRatedPoint(), p.getNumOfRater());
                } else {
                    Outlet o = pa.getOutlet();
                    os = new OutletState(o.getId(), o.getName(), o.isActive());
                }
                
                pas = new PartnerAccountState(pa.getUsername(), pa.getIC(), pa.getFirstName(), pa.getLastName(), pa.getAddress1(), pa.getAddress2(), pa.getPostalCode(), pa.getCountryCode(), pa.getPhone(), pa.getEmail(), pa.getCountry(), pa.getProvince(), pa.getCity(), pa.getTimezone(), pa.isActive(), pa.isActivated(), pa.getAccountLevel(), pa.getRegisteredDate(), listOfPrivileges, ps, os);
            } else pas = new PartnerAccountState(pa.isActive(), pa.isActivated());
            return pas;
        }
    }

    @Override
    public boolean checkPrivilege(String username, int requiredPrivilege) {
        PartnerAccount pa = em.find(PartnerAccount.class, username);
        System.out.println(pa.getAccountLevel());
        if (pa.getAccountLevel() == Constants.ACCOUNT_LEVEL_ROOT) return true; //root level account
        else {
            for (PartnerPrivilege pp : pa.getListOfPrivileges()) {
                if (pp.getId() == requiredPrivilege) return true;
            }
            return false;
        }
    }
    
    @Override
    public boolean checkAccountLevel(String username, int requiredAccountLevel) {
        PartnerAccount pa = em.find(PartnerAccount.class, username);
        if (pa.getAccountLevel() >= requiredAccountLevel) return true;
        else return false;
    }
    
    @Override
    public boolean checkAccountLevel(String username1, String username2) {
        PartnerAccount pa1 = em.find(PartnerAccount.class, username1);
        PartnerAccount pa2 = em.find(PartnerAccount.class, username2);
        return pa1.getAccountLevel() >= pa2.getAccountLevel();
    }

    @Override
    public List<PartnerPrivilegeState> getFullListOfPrivileges() {
        Query q = em.createQuery("SELECT P FROM PartnerPrivilege");
        List<PartnerPrivilegeState> listOfPrivileges = new ArrayList<PartnerPrivilegeState>();
        for (PartnerPrivilege pp : (List<PartnerPrivilege>) q.getResultList()) {
            PartnerPrivilegeState pps = new PartnerPrivilegeState(pp.getId(), pp.getName(), pp.getDescription(), pp.getCreatedDate());
            listOfPrivileges.add(pps);
        }
        return listOfPrivileges;
    }
    
    //Private methods of Partner Bean:
    private String getUniqueID() {
        int NUM_CHARS = 20;
        String chars = "abcdefghijklmonpqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        Random r = new Random();
        char[] buf = new char[NUM_CHARS];

        for (int i = 0; i < buf.length; i++) {
            buf[i] = chars.charAt(r.nextInt(62));
        }

        return new String(buf);
    }
    
    private void sendEmail(int msgType, String recipient, String link, String... args) {
        try {
            Connection      queueConnection = queueConnectionFactory.createConnection();
            Session         queueSession    = queueConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
            MessageProducer queueProducer   = queueSession.createProducer(emailQueue);
            MapMessage      msg             = queueSession.createMapMessage();
            //Plug in all data available and send the message
            msg.setInt("msgType", msgType);
            msg.setString("recipient", recipient);
            if (link != null) msg.setString("link", link);
            int i = 1;
            for (String str : args) {
                msg.setString("str"+i, str);
                i++;
            }
            queueProducer.send(msg);
            queueConnection.close();
        } catch (JMSException ex) {
            Logger.getLogger(CustomerBean.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
 
    //CUBE FUNCTIONS
    
    
    /*@Override
    public List<Cubes> getCubes() {
        Query query = em.createQuery("SELECT c FROM Cube c ");
        List stateSet = new ArrayList<CubeState>();
        for (Object o: query.getResultList()) {
            Cubes c = (Cubes)o;
            CubeState cs = new CubeState(c);
            stateSet.add(cs);
        }
        return stateSet;
    }*/
    
    @Override
    public Cubes viewCube(long cubeId, long partnerId) {
        Partner partner = em.find(Partner.class, partnerId);
        if (partner == null) {
            return null;
        }
        else {
            Cubes cube = em.find(Cubes.class, cubeId);
            if (cube.getCategory().getPartner().getId() != partnerId) { //check whether the partner is the owner of the cube to be viewed
                return null;
            }
            else {
                return cube;
            }
        }
    }
    
    @Override
    public int updateCube(long cubeId, long partnerId, long termsId, String name, String description, int type, int discount, int price, int redeemPrice, int additionalLoyaltyPoint, int maxNumOfBuyers, long startDate, long endDate) {
        Cubes cube = em.find(Cubes.class, cubeId);
        if (cube == null) {
            return Constants.STATUS_NOT_FOUND;
        }
        else {
            Partner partner = em.find(Partner.class, partnerId);
            if (partner == null) {
                return Constants.STATUS_NOT_FOUND;
            }
            else {
                if (cube.getCategory().getPartner().getId() != partnerId) { //check whether the partner is the owner of the cube to be viewed
                    return Constants.STATUS_FAILED;
                }
                else {
                    if (cube.getCategory().isActive() == true) {
                        return Constants.STATUS_FAILED;
                    }
                    else {
                        TermsAndConditions terms = em.find(TermsAndConditions.class, termsId);
                        if (terms == null) {
                            return Constants.STATUS_NOT_FOUND;
                        }
                        else {
                            cube.setName(name);
                            cube.setDescription(description);
                            cube.setType(type);
                            cube.getLatestItemDetails().setPrice(price);
                            cube.getLatestItemDetails().setDiscount(discount);
                            cube.getLatestItemDetails().setRedeemPrice(redeemPrice);
                            cube.getLatestItemDetails().setAdditionalLoyaltyPoint(additionalLoyaltyPoint);
                            cube.setMaxNumOfBuyers(maxNumOfBuyers);
                            cube.setStartDate(startDate);
                            cube.setEndDate(endDate);
                            cube.setTermsAndConditions(terms);
                            em.flush();
                            return Constants.STATUS_SUCCESSFUL;
                        }
                    }
                }
            }
        }
    }
    
    @Override
    public int delCube(long cubeId, long partnerId) {
        Cubes cube = em.find(Cubes.class, cubeId);
        if (cube == null) {
            return Constants.STATUS_NOT_FOUND;
        }
        else {
            Partner partner = em.find(Partner.class, partnerId);
            if (partner == null) {
                return Constants.STATUS_NOT_FOUND;
            }
            else if (cube.getCategory().getPartner() != partner) {
                return Constants.STATUS_FAILED;
            }
                em.flush();
                em.remove(cube);
                em.flush();
                return Constants.STATUS_SUCCESSFUL;
            }
        }
    
    @Override
    public int requestCubeActivation(long cubeId, long partnerId) {
        Cubes cube = em.find(Cubes.class, cubeId);
        if (cube == null) {
            return Constants.STATUS_NOT_FOUND;
        }
        else {
            Partner partner = em.find(Partner.class, partnerId);
            if (partner == null) {
                return Constants.STATUS_NOT_FOUND;
            }
            else {
                if (cube.getSequence() != 0) {
                    return Constants.STATUS_FAILED;
                }
                else {
                    cube.setSequence(Constants.LAST_SEQUENCE_NUMBER + 1);
                    Constants.LAST_SEQUENCE_NUMBER++;
                    return Constants.STATUS_SUCCESSFUL;
                }
            }
        }
    }
    
    @Override
    public int removeCubeActivation(long cubeId, long partnerId) {
        Cubes cube = em.find(Cubes.class, cubeId);
        if (cube == null) {
            return Constants.STATUS_NOT_FOUND;
        }
        else {
            Partner partner = em.find(Partner.class, partnerId);
            if (partner == null) {
                return Constants.STATUS_NOT_FOUND;
            }
            else {
                if (cube.getSequence() != 0) {
                    return Constants.STATUS_FAILED;
                }
                else {
                    cube.setSequence(0);
                    Constants.LAST_SEQUENCE_NUMBER--;
                    reorderCubesSequence();
                    return Constants.STATUS_SUCCESSFUL;
                }
            }
        }
    }

    
    @Override
    public int checkVoucher(long voucherId, long partnerId) {
        Voucher voucher = em.find(Voucher.class, voucherId);
        if (voucher == null) {
            return Constants.STATUS_NOT_FOUND;
        }
        else {
            Partner partner = em.find(Partner.class, partnerId);
            if (partner == null) {
                return Constants.STATUS_NOT_FOUND;
            }
            else {
                if (voucher.getItem().getCategory().getPartner().getId() != partnerId) { //check whether the partner is the owner of the cube to be viewed
                    return Constants.STATUS_FAILED;
                }
                else {
                    if (voucher.isUsed() == true) {
                        return Constants.STATUS_FAILED;
                    }
                    else {
                        return Constants.STATUS_SUCCESSFUL;
                    }
                }
            }
        }
    }
    
    
    @Override
    public String redeemVoucher(long voucherId, long partnerId) {
        Voucher voucher = em.find(Voucher.class, voucherId);
        if (voucher == null) {
            return "" + Constants.STATUS_NOT_FOUND;
        }
        else {
            Partner partner = em.find(Partner.class, partnerId);
            if (partner == null) {
                return "" + Constants.STATUS_NOT_FOUND;
            }
            else {
                if (voucher.getItem().getCategory().getPartner().getId() != partnerId) { //check whether the partner is the owner of the cube to be viewed
                    return "" + Constants.STATUS_FAILED;
                }
                else {
                    if (voucher.isUsed() == true) {
                        DateTime date = new DateTime(voucher.getRedeemedDate());
                        return ("The voucher " + voucher.getId() + " was redeemed on the " + date.toString() + ".");
                    }
                    else {
                        voucher.setUsed(true);
                        voucher.setRedeemedDate(System.currentTimeMillis());
                        return ("The voucher " + voucher.getId() + " is redeemed.");
                    }
                }
            }
        }
    }
    
    public int reorderCubesSequence() {
        int currentSeq = Constants.CURRENT_SEQUENCE_NUMBER;
        Query q = em.createQuery("SELECT C FROM Cubes C");
        while (Constants.CURRENT_SEQUENCE_NUMBER != Constants.LAST_SEQUENCE_NUMBER) {
            for (Cubes c : (List<Cubes>) q.getResultList()) {
                if (c.getSequence() == Constants.CURRENT_SEQUENCE_NUMBER) {
                    currentSeq++;
                    break;
                }
            }
        }
        return Constants.STATUS_SUCCESSFUL;
    }
}

    
    
